/* Copyright (C) 1997-2005, Antony L Hosking.
 * All rights reserved.  */
package Canon;

import java.util.List;

import Translate.Tree;
import Translate.Tree.Exp.*;
import Translate.Tree.Stm.*;

public class Print implements Tree.Visitor<Void, Void> {
    java.io.PrintWriter out;

    public Print(java.io.PrintWriter o, List<Tree.Stm> stms) {
        out = o;
        for (Tree.Stm s : stms)
            s.accept(this, null);
        o.flush();
    }

    public Print(java.io.PrintWriter o, Tree.Stm s) {
        out = o;
        s.accept(this, null);
        o.flush();
    }

    private void sayln(String o) {
        out.println(o);
        out.flush();
    }

    private void say(String o) {
        out.print(o);
    }

    private void sayln(Object o) {
        out.println(o.toString());
        out.flush();
    }

    private void say(Object o) {
        out.print(o.toString());
    }

    public Void visit(SEQ s, Void _) {
        throw new Error();
    }

    public Void visit(LABEL s, Void _) {
        sayln(s.label + ":");
        return _;
    }

    public Void visit(JUMP s, Void _) {
        if (!Tree.isAtom(s.exp))
            throw new Error();
        say("\tjump ");
        s.exp.accept(this, _);
        sayln("");
        return _;
    }

    public Void visit(CJUMP s, Void _) {
        String op;
        switch (s.op) {
        case BEQ:
            op = "beq";
            break;
        case BNE:
            op = "bne";
            break;
        case BLT:
            op = "blt";
            break;
        case BGT:
            op = "bgt";
            break;
        case BLE:
            op = "ble";
            break;
        case BGE:
            op = "bge";
            break;
        default:
            throw new Error();
        }
        if (!(Tree.isAtom(s.left) && Tree.isAtom(s.right)))
            throw new Error();
        say("\t" + op);
        say(" ");
        s.left.accept(this, _);
        say(" ");
        s.right.accept(this, _);
        say(" ");
        say(s.iftrue);
        say(" ");
        sayln(s.iffalse);
        return _;
    }

    public Void visit(MOVE s, Void _) {
        if (!(s.dst instanceof TEMP || Tree.isAtom(s.src)))
            throw new Error();
        say("\t");
        s.dst.accept(this, _);
        say(" := ");
        s.src.accept(this, _);
        sayln("");
        return _;
    }

    public Void visit(ESTM s, Void _) {
        if (!(s.exp instanceof CALL))
            throw new Error();
        say("\t");
        s.exp.accept(this, _);
        sayln("");
        return _;
    }

    public Void visit(BINOP e, Void _) {
        String op;
        switch (e.op) {
        case ADD:
            op = "+";
            break;
        case SUB:
            op = "-";
            break;
        case MUL:
            op = "*";
            break;
        case DIV:
            op = "/";
            break;
        case AND:
            op = "&&";
            break;
        case OR:
            op = "||";
            break;
        case SLL:
            op = "<<";
            break;
        case SRL:
            op = ">>>";
            break;
        case SRA:
            op = ">>";
            break;
        case XOR:
            op = "^";
            break;
        case DIVU:
            op = "/u";
            break;
        default:
            throw new Error();
        }
        if (!(Tree.isAtom(e.left) && Tree.isAtom(e.right)))
            throw new Error();
        e.left.accept(this, _);
        say(" " + op + " ");
        e.right.accept(this, _);
        return _;
    }

    public Void visit(MEM e, Void _) {
        if (!Tree.isAtom(e.exp))
            throw new Error();
        e.exp.accept(this, _);
        say("[");
        say(e.offset.value);
        say("]");
        return _;
    }

    public Void visit(TEMP e, Void _) {
        say(e.temp);
        return _;
    }

    public Void visit(ESEQ e, Void _) {
        throw new Error();
    }

    public Void visit(NAME e, Void _) {
        say(e.label);
        return _;
    }

    public Void visit(CONST e, Void _) {
        say("#");
        say(e.value);
        return _;
    }

    public Void visit(CALL e, Void _) {
        if (!Tree.isAtom(e.func))
            throw new Error();
        e.func.accept(this, _);
        say("(");
        if (e.args.length > 0) {
            if (!Tree.isAtom(e.args[0]))
                throw new Error();
            e.args[0].accept(this, _);
            for (int i = 1; i < e.args.length; i++) {
                if (!Tree.isAtom(e.args[i]))
                    throw new Error();
                say(", ");
                e.args[i].accept(this, _);
            }
        }
        say(")");
        return _;
    }
}
